package com.qiuling.iot.service.impl;

import com.github.pagehelper.PageHelper;
import com.qiuling.iot.Exception.BusinessException;
import com.qiuling.iot.Exception.code.BaseResponseCode;
import com.qiuling.iot.constants.Constant;
import com.qiuling.iot.entity.SysRole;
import com.qiuling.iot.mapper.SysRoleMapper;
import com.qiuling.iot.service.*;
import com.qiuling.iot.utils.PageUtil;
import com.qiuling.iot.utils.RedisUtils;
import com.qiuling.iot.utils.TokenSettings;
import com.qiuling.iot.vo.req.AddRoleReqVO;
import com.qiuling.iot.vo.req.RolePageReqVO;
import com.qiuling.iot.vo.req.RolePermissionOperationReqVO;
import com.qiuling.iot.vo.req.RoleUpdateReqVO;
import com.qiuling.iot.vo.resp.PageVO;
import com.qiuling.iot.vo.resp.PermissionRespNodeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author：zhangqiang
 * @Description：
 * @Date：Created in 19:53 2020/2/11
 * @Modified By：
 */
@Service
@Slf4j
@Transactional(readOnly = true)
public class RoleServiceImpl implements RoleService {

    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private RolePermissionService rolePermissionService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private TokenSettings tokenSettings;

    @Override
    public PageVO<SysRole> pageInfo(RolePageReqVO vo) {
        PageHelper.offsetPage(vo.getPageNum(), vo.getPageSize());
        List<SysRole> sysRoles = sysRoleMapper.selectAll(vo);
        return PageUtil.getPageVO(sysRoles);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysRole addRole(AddRoleReqVO vo) {
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(vo, sysRole);
        sysRole.setId(UUID.randomUUID().toString());
        sysRole.setCreateTime(new Date());
        int i = sysRoleMapper.insertSelective(sysRole);
        if (i != 1) {
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        if (vo.getPermissions() != null && !vo.getPermissions().isEmpty()) {
            RolePermissionOperationReqVO operationReqVO = new RolePermissionOperationReqVO();
            operationReqVO.setRoleId(sysRole.getId());
            operationReqVO.setPermissionIds(vo.getPermissions());
            rolePermissionService.addRolePermission(operationReqVO);
        }
        return sysRole;
    }

    @Override
    public List<SysRole> selectAll() {
        return sysRoleMapper.selectAll(new RolePageReqVO());
    }

    @Override
    public SysRole detailInfo(String id) {
        //通过id获取角色信息
        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(id);
        if (sysRole == null) {
            log.error("传入 的 id:{}不合法", id);
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        //获取所有权限菜单权限树
        List<PermissionRespNodeVO> permissionRespNodeVOS = permissionService.selectAllTree();
        //获取该角色拥有的菜单权限
        List<String> permissionIdsByRoleId = rolePermissionService.getPermissionIdsByRoleId(id);
        Set<String> checkList = new HashSet<>(permissionIdsByRoleId);
        //遍历菜单权限树的数据
        setChecked(permissionRespNodeVOS, checkList);
        sysRole.setPermissionRespNode(permissionRespNodeVOS);
        return sysRole;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(RoleUpdateReqVO vo) {
        //保存角色基本信息
        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(vo.getId());
        if (null == sysRole) {
            log.error("传入 的 id:{}不合法", vo.getId());
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        BeanUtils.copyProperties(vo, sysRole);
        sysRole.setUpdateTime(new Date());
        int count = sysRoleMapper.updateByPrimaryKeySelective(sysRole);
        if (count != 1) {
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //修改该角色和菜单权限关联数据
        RolePermissionOperationReqVO reqVO = new RolePermissionOperationReqVO();
        reqVO.setRoleId(vo.getId());
        reqVO.setPermissionIds(vo.getPermissions());
        rolePermissionService.addRolePermission(reqVO);
        //标记关联用户
        List<String> userIdsBtRoleId = userRoleService.getUserIdsBtRoleId(vo.getId());
        if (!userIdsBtRoleId.isEmpty()) {
            for (String userId :
                    userIdsBtRoleId) {
                /**
                 * 标记用户 在用户认证的时候判断这个是否主动刷过
                 */
                redisUtils.set(Constant.JWT_REFRESH_KEY + userId, userId, tokenSettings.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);

                /**
                 * 清除用户授权数据缓存
                 */
                redisUtils.delete(Constant.IDENTIFY_CACHE_KEY + userId);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletedRole(String roleId) {
        //就更新删除的角色数据
        SysRole sysRole = new SysRole();
        sysRole.setId(roleId);
        sysRole.setDeleted(0);
        sysRole.setUpdateTime(new Date());
        int i = sysRoleMapper.updateByPrimaryKeySelective(sysRole);
        if (i != 1) {
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //角色菜单权限关联数据删除
        rolePermissionService.removeByRoleId(roleId);
        List<String> userIdsBtRoleId = userRoleService.getUserIdsBtRoleId(roleId);
        //角色用户关联数据删除
        userRoleService.removeUserRoleId(roleId);
        //把跟该角色关联的用户标记起来，需要刷新token
        if (!userIdsBtRoleId.isEmpty()) {
            for (String userId :
                    userIdsBtRoleId) {
                /**
                 * 标记用户 在用户认证的时候判断这个是否主动刷过
                 */
                redisUtils.set(Constant.JWT_REFRESH_KEY + userId, userId, tokenSettings.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
                /**
                 * 清除用户授权数据缓存
                 */
                redisUtils.delete(Constant.IDENTIFY_CACHE_KEY + userId);
            }
        }
    }

    @Override
    public List<String> getRoleNames(String userId) {
        List<SysRole> sysRoles = getRoleInfoByUserId(userId);
        if (null == sysRoles || sysRoles.isEmpty()) {
            return null;
        }
        List<String> list = new ArrayList<>();
        for (SysRole sysRole : sysRoles) {
            list.add(sysRole.getName());
        }
        return list;
    }

    @Override
    public List<SysRole> getRoleInfoByUserId(String userId) {
        List<String> roleIds = userRoleService.getRoleIdsByUserId(userId);
        if (roleIds.isEmpty()) {
            return null;
        }
        return sysRoleMapper.getRoleInfoByIds(roleIds);
    }

    /**遍历节点
     * @param list
     * @param checkList
     */
    private void setChecked(List<PermissionRespNodeVO> list, Set<String> checkList) {

        for (PermissionRespNodeVO node : list) {
            /**
             * 子集选中从它往上到跟目录都被选中，父级选中从它到它所有的叶子节点都会被选中
             * 这样我们就直接遍历最底层及就可以了
             */
            if (checkList.contains(node.getId()) && (node.getChildren() == null || node.getChildren().isEmpty())) {
                node.setChecked(true);
            }
            setChecked((List<PermissionRespNodeVO>) node.getChildren(), checkList);

        }
    }
}
